package ginHelper

import (
	"dcim/pkg/generic-go-kit/core"
	"dcim/pkg/generic-go-kit/utils"
	"errors"
	"github.com/gin-gonic/gin"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	"github.com/nats-io/nats.go"
	"strings"
)

func DefaultGetValidParams(c *gin.Context, params interface{}) error {
	//获取验证器
	val, _ := c.Get(utils.ValidatorKey)
	valid, _ := val.(*validator.Validate)
	//获取翻译器
	tran, _ := c.Get(utils.TranslatorKey)
	trans, _ := tran.(ut.Translator)
	err := valid.Struct(params)
	//如果数据效验不通过，则将所有err以切片形式输出
	if err != nil {
		errs := err.(validator.ValidationErrors)
		sliceErrs := []string{}
		for _, e := range errs {
			//使用validator.ValidationErrors类型里的Translate方法进行翻译
			sliceErrs = append(sliceErrs, e.Translate(trans))
		}
		return errors.New(strings.Join(sliceErrs, ","))
	}
	return nil
}

type DecodeRequestFunc func(c *gin.Context) (interface{}, error)

func DecodeRequest[T any](c *gin.Context) (interface{}, error) {
	var req T

	// 默认绑定query参数
	err := c.ShouldBindQuery(&req)
	if err != nil {
		return nil, err
	}

	if c.Request.Method != "GET" {
		// 非GET请求从body中获取数据
		err := c.ShouldBindJSON(&req)
		if err != nil {
			return nil, err
		}
	}

	// 路径参数不为空则优先取值路径参数
	if len(c.Params) > 0 {
		err := c.ShouldBindUri(&req)
		if err != nil {
			return nil, err
		}
	}

	// 参数校验
	err = DefaultGetValidParams(c, req)
	if err != nil {
		return nil, err
	}

	return req, nil
}

func MakeNatsProxyHandler(n *nats.Conn, sub string, dec DecodeRequestFunc, options ...core.PublisherOption) gin.HandlerFunc {

	return func(c *gin.Context) {

		req, err := dec(c)

		if err != nil {
			panic(err)
		}

		var ops []core.PublisherOption
		ops = append(ops, core.PublisherBefore(core.SetNatsMsgFormContext))

		if len(options) > 0 {
			ops = append(ops, options...)
		}

		res, err := core.MakeNatsClientEndpoint(n, sub, ops...)(c.Request.Context(), req)
		if err != nil {
			panic(err)
		}
		c.JSON(200, res)

	}

}

func MakeNatsProxyWithCallbackHandler(n *nats.Conn, sub string, dec DecodeRequestFunc, callback gin.HandlerFunc, options ...core.PublisherOption) gin.HandlerFunc {

	return func(c *gin.Context) {

		req, err := dec(c)

		if err != nil {
			panic(err)
		}

		var ops []core.PublisherOption
		ops = append(ops, core.PublisherBefore(core.SetNatsMsgFormContext))

		if len(options) > 0 {
			ops = append(ops, options...)
		}

		res, err := core.MakeNatsClientEndpoint(n, sub, ops...)(c.Request.Context(), req)
		if err != nil {
			panic(err)
		}
		c.JSON(200, res)

		defer callback(c)
	}

}
